﻿#region Copyright & licence

// This file is part of Refix.
// 
// Refix is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
// 
// Refix is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License along with Refix.  If not, see <http://www.gnu.org/licenses/>.
// 
// Copyright (C) 2010-11 David Musgrove and others.

#endregion

using System;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Reflection;

using NUnit.Framework;
using Moq;

using Refix.Core.Repository;

namespace Refix.Core.Tests.Repository
{
    [TestFixture]
    public class RepositoryTest
    {
        private string _solutionRootDirectory;
        private string _repoPath;

        [TestFixtureSetUp]
        public void TextFixtureSetUp()
        {
            var fileInfo = new FileInfo(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath);
            _solutionRootDirectory = fileInfo.Directory.Parent.Parent.Parent.FullName;
            _repoPath = Path.Combine(_solutionRootDirectory, ".testrefixrepo");
            ConfigurationManager.AppSettings.Set("Refix.Repository.Local", _repoPath);
            Environment.SetEnvironmentVariable(EnvironmentVariables.RefixLocalRepository, null,
                                               EnvironmentVariableTarget.Process);
            Environment.SetEnvironmentVariable(EnvironmentVariables.RefixRemoteRepository, null,
                                               EnvironmentVariableTarget.Process);
        }

        [Test]
        public void GetComponent_Returns_Component()
        {
            var localRepository = new LocalRepository();
            Component component = localRepository.GetComponent("Refix.Test.B");
            Assert.IsNotNull(component, "Repository returned null for Refix.Test.B.");
            Assert.AreEqual("Refix.Test.B", component.Name, "Repository returned component with wrong name.");
        }

        [Test]
        public void GetComponent_Returns_Component_With_Versions()
        {
            var localRepository = new LocalRepository();
            Component component = localRepository.GetComponent("Refix.Test.B");
            Assert.AreEqual(4, component.Versions.Count,
                            "Repository returned wrong number of versions for Refix.Test.B.");
            ComponentVersion version = component.Versions.First(v => v.Number == "0.1.0.2");
            Assert.IsNotNull(version, "Repository did not return version 0.1.0.2 of Refix.Test.B.");
            Assert.AreEqual(1, version.AlternativeVersions.Count,
                            "Repository did not return alternative versions for version 0.1.0.2 of Refix.Test.B.");
            Assert.AreEqual("0.1.0.2+", version.AlternativeVersions[0].Number,
                            "Repository did not return correct alternative version for version 0.1.0.2 of Refix.Test.B.");
            Assert.AreEqual(1, version.Dependencies.Count,
                            "Repository did not return dependencies for version 0.1.0.2 of Refix.Test.B.");
            Assert.AreEqual("Refix.Test.A", version.Dependencies[0].Name,
                            "Repository did not return correct dependency name for version 0.1.0.2 of Refix.Test.B.");
            Assert.AreEqual("0.1.0.1", version.Dependencies[0].Version,
                            "Repository did not return correct dependency version for version 0.1.0.2 of Refix.Test.B.");
        }

        [Test]
        public void GetComponent_Returns_Null_For_Unknown_Assembly()
        {
            var remoteRepository = new Mock<RemoteRepository>("testurl", _repoPath);
            var localRepository = new LocalRepository(_repoPath, remoteRepository.Object);
            remoteRepository.Setup(x => x.DownloadVersion(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).Returns(false);
            Component component = localRepository.GetComponent("Unknown.Assembly");
            Assert.IsNull(component, "Unknown assembly didn't return a null component.");
            remoteRepository.Verify();
        }

        [Test]
        public void PutAssembly_And_RemoveAssembly_Work()
        {
            var localRepository = new LocalRepository();
            string newAssemblyLocation = Path.Combine(_solutionRootDirectory, "TestFiles\\Refix.Test.A.dll");
            Assembly assembly = Assembly.ReflectionOnlyLoadFrom(newAssemblyLocation);
            Component componentBefore = localRepository.GetComponent("Refix.Test.A");
            Assert.AreEqual(4, componentBefore.Versions.Count, "Refix.Test.A had wrong number of versions before test.");
            componentBefore.Versions.Add(new ComponentVersion {Number = "0.1.0.5"});
            localRepository.PutComponent(componentBefore);
            localRepository.PutAssembly(assembly, null);
            Component componentDuring = localRepository.GetComponent("Refix.Test.A");
            Assert.AreEqual(5, componentDuring.Versions.Count, "Refix.Test.A had wrong number of versions during test.");
            Assert.True(
                File.Exists(Path.Combine(_solutionRootDirectory,
                                         ".testrefixrepo\\Refix\\Test\\A\\0.1.0.5\\Refix.Test.A.dll")),
                "DLL file not copied into repository.");
            Assert.True(
                File.Exists(Path.Combine(_solutionRootDirectory,
                                         ".testrefixrepo\\Refix\\Test\\A\\0.1.0.5\\Refix.Test.A.pdb")),
                "PDB file not copied into repository.");
            Assert.True(
                File.Exists(Path.Combine(_solutionRootDirectory,
                                         ".testrefixrepo\\Refix\\Test\\A\\0.1.0.5\\Refix.Test.A.xml")),
                "XML file not copied into repository.");
            Assert.True(
                File.Exists(Path.Combine(_solutionRootDirectory,
                                         ".testrefixrepo\\Refix\\Test\\A\\0.1.0.5\\Refix.Test.A.dll.config")),
                "Config file not copied into repository.");
            localRepository.RemoveAssembly(componentDuring, "0.1.0.5");
            Component componentAfter = localRepository.GetComponent("Refix.Test.A");
            Assert.AreEqual(4, componentAfter.Versions.Count, "Refix.Test.A had wrong number of versions after test.");
            Assert.False(
                Directory.Exists(Path.Combine(_solutionRootDirectory, ".testrefixrepo\\Refix\\Test\\A\\0.1.0.5")));
        }

        [Test]
        public void GetComponentVersion_Adds_Version_To_Returned_Components()
        {
            var remoteRepository = new Mock<RemoteRepository>("testurl", _repoPath);
            var localRepository = new LocalRepository(_repoPath, remoteRepository.Object);
            Component componentBefore = localRepository.GetComponent("Refix.Test.A");
            Assert.AreEqual(4, componentBefore.Versions.Count, "Refix.Test.A had wrong number of versions before test.");
            remoteRepository.Setup(x => x.DownloadVersion(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).Callback(() =>
                                                                                                                                    {
                                                                                                                                        componentBefore.Versions.Add(new ComponentVersion { Number = "0.1.0.5" });
                                                                                                                                        localRepository.PutComponent(componentBefore);                                                                                                                                        
                                                                                                                                    }).Returns(true);
            var component = localRepository.GetComponentVersion("Refix.Test.A", "0.1.0.5");
            Assert.IsNotNull(component);
            Component componentAfter = localRepository.GetComponent("Refix.Test.A");
            localRepository.RemoveAssembly(componentAfter, "0.1.0.5");
            Assert.AreEqual(4, componentAfter.Versions.Count, "Refix.Test.A had wrong number of versions after test.");
        }
    }
}
